If you manage memory manually, it’s your responsibility to delete
all memory created with new
, and to make sure it’s
delete
d once and only once. Ensuring this is done is error-prone, especially when your function can have early exit points.
Fortunately, the C++ language provides tools that automatically manage memory for you. Using them systematically makes the code simpler and more
robust without sacrificing performance.
This rule raises an issue when you use:
-
new
- you should prefer a factory function that returns a smart pointer, such as std::make_unique
or, if shared
ownership is required, std::make_shared
,
-
new[]
- you should prefer a container class, such as std::vector
,
-
delete
or delete[]
- if you followed the previous advice, there is no need to manually release memory.
If your compiler does not support make_unique
, it’s easy to write your own:
template<typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&&... args) {
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
Noncompliant code example
void f() {
auto c = new Circle(0, 0, 5);
c->draw();
delete c;
}
Compliant solution
void f() {
auto c = make_unique<Circle>(0, 0, 5);
c->draw();
unique_ptr<Circle> c2{new Circle(0, 0, 5)}; // Clumsy, but still compliant by exception
}
Exceptions
If the result of a new is immediately passed as an argument to a function, we assume that the function takes ownership of the newly created object,
and won’t raise an issue.